#include "Manager.h"

	// constructor/destructor
	Manager::Manager() 
		: m_nLocks(0) 
	{
		m_dumpFile.open(COMP_DUMP_FILE,fstream::trunc|fstream::out);
		if(!m_dumpFile.is_open())
		{
			EXCEPTION("")
		}
	}

	Manager::~Manager() 
	{
	}

	void Manager::AddObject(const ObjPtr& obj)
	{
		if(!obj)
		{
			EXCEPTION("obj not exists")
		}
		m_objects[obj->GetName()]=obj;
		obj->m_manager=this;
	}

	void Manager::AddComponent(const ObjectName& oid, const CompPtr& component )
	{
		if(!m_objects[oid])
		{
			EXCEPTION("object not exists")
		}

		if(!component)
		{
			EXCEPTION("component not creat")
		}

		// can only add once
		if (component->m_manager != 0) 
		{
			EXCEPTION("component already registed")
		}
		
		CompName compName=component->GetName();
		CompId compId=component->GetId();
		// set the object manager
		component->m_manager = this;

		// set the owner of the component
		component->setOwner(oid);

		m_components[compId]=component;

		// we add the component
		if (! m_objects[oid]->AddComponent(component)) 
		{
			EXCEPTION("failed to add componnet")
		}

		// let the component know
		component->AddedToObject();

		// lock this request id

		if(fGlobalRequests[REQ_COMPONENT][compName].empty())
			return;
		
		ActivateLock(REQ_COMP(compName));

		for (list<RegisteredComponent>::iterator it = fGlobalRequests[REQ_COMPONENT][compName].begin(); it != fGlobalRequests[REQ_COMPONENT][compName].end(); ++it) 
		{
			if (it->cid != compId) 
			{
				(*it).callback(MSG_COMP(compId,component));
			}
		}

		// release the lock
		ReleaseLock(REQ_COMP(compName));
	}
	
	void Manager::RegisterLocalRequest(const ComponentRequest& req, const RegisteredComponent& reg) 
	{

		// if this request is locked, postpone the processing
		if(m_requestLocks[req.type].find(req.id)!=m_requestLocks[req.type].end())
		{
			if (m_requestLocks[req.type][req.id].locked) 
			{
				m_requestLocks[req.type][req.id].pendingLocalRequests.push_back(pair<ComponentRequest, RegisteredComponent>(req, reg));
				return;
			}
		}

		// forward to appropriate object
		CompPtr tmpPtr=m_components[reg.cid];
		ObjectName oid=tmpPtr->GetOwnerId();
		
		if(!tmpPtr)
			EXCEPTION("")
			
		m_objects[oid]->RegisterRequest(req, reg);

		if (req.type != REQ_COMPONENT) return;

		ActivateLock(req);

		m_objects[oid]->RegisterComponent(req,reg);
		// release the lock
		ReleaseLock(req);
	}

	// register a global request
	void Manager::RegisterGlobalRequest(const ComponentRequest& req, const RegisteredComponent& reg) 
	{

		// if this request is locked, postpone the processing
		if(m_requestLocks[req.type].find(req.id)!=m_requestLocks[req.type].end())
		{
			if (m_requestLocks[req.type][req.id].locked) 
			{
				m_requestLocks[req.type][req.id].pendingGlobalRequests.push_back(pair<ComponentRequest, RegisteredComponent>(req, reg));
				Dump();
				return;
			}
		}

		fGlobalRequests[req.type][req.id].push_back(reg);
		CompPtr tmpComp=m_components[reg.cid];
		if(!tmpComp)
			EXCEPTION("")

		ObjectName objId = tmpComp->GetOwnerId();

		m_objects[objId]->RegisterRequest(req, reg);

		// if we want the previously created components as well, we process them
		if (req.type == REQ_MESSAGE) return;

		// activate the lock on this id
		ActivateLock(req);

		for(CompMap::iterator iter=m_components.begin();iter!=m_components.end();iter++)
		{
			if(iter->second->GetName()==req.id.comp)
			{
				reg.callback(MSG_COMP(iter->second->GetId(),iter->second));
			}
		}

		ReleaseLock(req);
	}

	// activate lock
	void Manager::ActivateLock(const ComponentRequest& req) 
	{
		if(m_requestLocks[req.type].find(req.id)!=m_requestLocks[req.type].end())
		{
			if (m_requestLocks[req.type][req.id].locked==true) 
			{
				EXCEPTION("request already locked");
			}
		}
		// one more lofk
		++m_nLocks;

		// activate the lockf
		m_requestLocks[req.type][req.id]=RequestLock();
		m_requestLocks[req.type][req.id].locked = true;
	}


	// release the lock, process the pending global and local requests
	void Manager::ReleaseLock(const ComponentRequest& req) 
	{

		// lock
		if(m_requestLocks[req.type].find(req.id)==m_requestLocks[req.type].end())
		{
			EXCEPTION("request never been locked")
		}
		RequestLock& lock = m_requestLocks[req.type][req.id];

		// must be locked!
		if(!lock.locked)
		{
			EXCEPTION("request never been locked")
		}

		// release the lock
		lock.locked = false;

		// one lock less
		--m_nLocks;

		// copy the pending requests
		list<pair<ComponentRequest, RegisteredComponent> > pendingGlobal = lock.pendingGlobalRequests;
		list<pair<ComponentRequest, RegisteredComponent> > pendingLocal = lock.pendingLocalRequests;
		lock.pendingGlobalRequests = list<pair<ComponentRequest, RegisteredComponent> >();
		lock.pendingLocalRequests = list<pair<ComponentRequest, RegisteredComponent> >();

		// process the global requests
		for (list<pair<ComponentRequest, RegisteredComponent> >::iterator it = pendingGlobal.begin(); it != pendingGlobal.end(); ++it) 
		{
			RegisterGlobalRequest(it->first, it->second);
		}

		// process the local requests
		for (list<pair<ComponentRequest, RegisteredComponent> >::iterator it = pendingLocal.begin(); it != pendingLocal.end(); ++it) 
		{
			RegisterLocalRequest(it->first, it->second);
		}
	}

	void Manager::SendMessage(const MsgId& msg, const boost::any payload)
	{
		SendGlobalMessage(REQ_MSG(msg),MSG_NOCOMP(payload));

	}

	// send a message to everyone
	void Manager::SendGlobalMessage(const ComponentRequest& req, const Message& msg)
	{
#ifdef _DEBUG
		if(req.type==REQ_MESSAGE&&req.id.msg==MSG_DUMP_ALL_MESSAGE)
			Dump();
#endif
		// activate the lock
		ActivateLock(req);

		// look for requests and forward them
		for (list<RegisteredComponent>::iterator it = fGlobalRequests[req.type][req.id].begin(); it != fGlobalRequests[req.type][req.id].end(); it++) 
		{
			(*it).callback(msg);
		}

		// release the lock
		ReleaseLock(req);
	}

	void Manager::SendMessageToObject(const ComponentRequest& req, const Message& msg, const ObjectName& id)
	{
#ifdef _DEBUG
		if(req.type==REQ_MESSAGE&&req.id.msg==MSG_DUMP_ALL_MESSAGE)
			Dump();
#endif
		// activate the lock
		ActivateLock(req);
		
		assert(m_objects[id]);
		m_objects[id]->ReceiveMessage(req,msg);
		
		// release the lock
		ReleaseLock(req);
	}

#ifdef _DEBUG
	void Manager::DumpObjects(ObjectMap::value_type objs)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		m_dumpFile<<"\tObject ID:"<<objs.first<<endl;
		//m_dumpFile<<objs.second->Dump()<<endl;
	}

	void Manager::DumpComponents(CompMap::value_type comps)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		m_dumpFile<<"\tComponent ID:"<<comps.first<<endl;

	}

	void Manager::DumpMessageReqs(std::pair<const RequestId,CallbackList> msg)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		m_dumpFile<<"\t\tRequest message ID:"<<msg.first<<endl;
		for(CallbackList::iterator iter=msg.second.begin();iter!=msg.second.end();iter++)
		{
			//m_dumpFile<<"Componnet ID:"<<iter->component->GetId()<<endl;
		}
	}

	void Manager::DumpComponentReqs(std::pair<const RequestId,CallbackList> comp)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		m_dumpFile<<"\t\tRequest componnets ID:"<<comp.first<<endl;
		for(CallbackList::iterator iter=comp.second.begin();iter!=comp.second.end();iter++)
		{
			//m_dumpFile<<iter->component->GetId()<<endl;
		}
	}

	void Manager::DumpRequests(GlobalRequestMap::value_type reqs)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		switch (reqs.first)
		{
		case REQ_MESSAGE:
			m_dumpFile<<"\tMessage request:"<<endl;
			for_each(reqs.second.begin(),reqs.second.end(),boost::bind(&Manager::DumpMessageReqs,this,_1));
			break;
		case REQ_COMPONENT:
			m_dumpFile<<"\tComponent request:"<<endl;
			for_each(reqs.second.begin(),reqs.second.end(),boost::bind(&Manager::DumpComponentReqs,this,_1));
			break;
		default:
			EXCEPTION("UNEXPECTED ERROR")
			break;
		}
	}

	void Manager::DumpComponentLocks(std::pair<const RequestId,RequestLock> compL)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		m_dumpFile<<"\t\tLock componnets req Id:"<<compL.first<<" status:"<<compL.second.locked<<endl;
	}

	void Manager::DumpMessageLocks(std::pair<const RequestId,RequestLock> msgL)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")
		m_dumpFile<<"\t\tLock message req Id:"<<msgL.first<<" status:"<<msgL.second.locked<<endl;
	}

	void Manager::DumpRequestLocks(GlobalRequestLockMap::value_type locks)
	{
		if(!m_dumpFile.is_open())
			EXCEPTION("dump file not open!")

		switch (locks.first)
		{
		case REQ_MESSAGE:
			m_dumpFile<<"\tMessage locks:"<<endl;
			for_each(locks.second.begin(),locks.second.end(),boost::bind(&Manager::DumpMessageLocks,this,_1));
			break;
		case REQ_COMPONENT:
			m_dumpFile<<"\tComponent locks:"<<endl;
			for_each(locks.second.begin(),locks.second.end(),boost::bind(&Manager::DumpComponentLocks,this,_1));
			break;
		default:
			EXCEPTION("UNEXPECTED ERROR")
			break;
		}

	}

	void Manager::Dump()
	{
		/*m_dumpFile<<"DumpComponents"<<endl;
		for_each(m_components.begin(),m_components.end(),boost::bind(&Manager::DumpComponents,this,_1));
		m_dumpFile<<"DumpObjects"<<endl;
		for_each(m_objects.begin(),m_objects.end(),boost::bind(&Manager::DumpObjects,this,_1));
		m_dumpFile<<"DumpRequests"<<endl;
		for_each(fGlobalRequests.begin(),fGlobalRequests.end(),boost::bind(&Manager::DumpRequests,this,_1));
		m_dumpFile<<"DumpRequestLock"<<endl;*/
		for_each(m_requestLocks.begin(),m_requestLocks.end(),boost::bind(&Manager::DumpRequestLocks,this,_1));
	}
#endif

	void Manager::DestoryComponent(const CompName& cid, const CompId& fid)
	{
	}
